package result

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"paper-pro/pkg/xerr"

	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/core/logx"
	"google.golang.org/grpc/status"
)

func writeSSE(w http.ResponseWriter, data string) {
	fmt.Fprintf(w, "data: %s\n\n", data)
}

func toJSONString[T any](data T) (string, error) {
	bytes, err := json.Marshal(data)
	if err != nil {
		return "", err
	}
	return string(bytes), nil
}

func flushSSEResult[T any](req *http.Request, w http.ResponseWriter, flusher http.Flusher, result T) {
	s, err := toJSONString(result)
	if err != nil {
		logx.WithContext(req.Context()).Errorf("【API-SSE-ERR】 : flushSSEResult failed: toJSONString error: %+v", err)
	}
	writeSSE(w, s)
	flusher.Flush()
}

func SSEResult(req *http.Request, w http.ResponseWriter, flusher http.Flusher, resp any, err error) {
	switch err {
	case nil:
		// 成功返回
		r := Success(resp)
		flushSSEResult(req, w, flusher, r)
	case io.EOF:
		// 成功结束
		return
	default:
		// 错误返回
		errCode := xerr.SERVER_COMMON_ERROR
		errMsg := "服务器开小差啦，稍后再来试一试"

		causeErr := errors.Cause(err)
		if e, ok := causeErr.(*xerr.CodeError); ok {
			// 自定义错误类型
			errCode = e.GetEreCode()
			errMsg = e.GetErrMsg()
		} else {
			if gstatus, ok := status.FromError(causeErr); ok { // grpc err 错误
				grpcCode := uint32(gstatus.Code())
				if xerr.IsCodeErr(grpcCode) { // 区分自定义错误跟系统底层、db等错误，底层、db错误不能返回给前端
					errCode = grpcCode
					errMsg = gstatus.Message()
				}
			}
		}

		logx.WithContext(req.Context()).Errorf("【API-SSE-ERR】 : %+v", err)

		flushSSEResult(req, w, flusher, Error(errCode, errMsg))
	}
}

// http 参数错误返回
func SSEParamErrorResult(r *http.Request, w http.ResponseWriter, flusher http.Flusher, err error) {
	errMsg := fmt.Sprintf("%s, %s", xerr.MapErrMsg(xerr.REQUEST_PARAM_ERROR), err.Error())
	flushSSEResult(r, w, flusher, Error(xerr.REQUEST_PARAM_ERROR, errMsg))
}
